
/*    This file is part of the Managarm operating system.
 *   Copyright (C) 2007, 2008, 2009  Alexander van der Grinten
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>. */

package org.managarm.jmanavalib.core;

public class VaInst extends VaObject {
	// pushs a literal onto the register stack
	public static final class InstLoad extends VaInst {
		public final VaLiteral literal;
		
		public InstLoad(VaLiteral literal) {
			this.literal = literal;
		}
	}
	
	// returns from a procedure
	public static final class InstReturn extends VaInst {
		public final int register;
		
		public InstReturn(int register) {
			this.register = register;
		}
	}
	
	// applies a binary operator to two registers
	// and push the result onto the register stack
	public static final class InstBinOperation extends VaInst {
		// operator constants
		public static final int OP_ARITH_ADD = 1;
		public static final int OP_ARITH_SUB = 2;
		public static final int OP_ARITH_MUL = 3;
		public static final int OP_ARITH_DIV = 4;
		public static final int OP_ARITH_MOD = 5;
		public static final int OP_ARITH_OR = 6;
		public static final int OP_ARITH_AND = 7;
		public static final int OP_ARITH_XOR = 8;
		public static final int OP_ARITH_SHL = 9;
		public static final int OP_ARITH_SHR = 10;
		public static final int OP_SETIF_EQUALS = 11;
		public static final int OP_SETIF_ABOVE = 12;
		public static final int OP_SETIF_BELOW = 13;
		
		public final int operator;
		public final int left;
		public final int right;
		
		public InstBinOperation(int operator,
				int left, int right) {
			this.operator = operator;
			this.left = left;
			this.right = right;
		}
	}
	
	// applies a unary operator to a register and
	// pushes the result onto the register stack
	public final static class InstUnOperation extends VaInst {
		public static final int OP_ARITH_NOT = 1;
		public static final int OP_ARITH_NEG = 2;
		public static final int OP_ARR_SIZE = 3;
		
		public final int operator;
		public final int operand;
		
		public InstUnOperation(int operator, int operand) {
			this.operator = operator;
			this.operand = operand;
		}
	}
	
	// jumps to/invokes a frame if the specified register contains true
	public static final class InstJump extends VaInst {
		public final int frameId;
		public final int register;
		private final int[] arguments;
		
		public InstJump(int frameid, int register, int[] arguments) {
			this.frameId = frameid;
			this.register = register;
			this.arguments = arguments.clone();
		}
		
		// returns the argument count
		public int getArgumentCnt() {
			return arguments.length;
		}
		
		// returns the argument register at "index"
		public int getArgument(int index) {
			return arguments[index];
		}
	}
	
	// invokes a method and pushs the results
	// onto the register stack
	public static final class InstInvoke extends VaInst {
		public final VaMthInfo mthInfo;
		public final int object;
		public final boolean virtual;
		public final boolean result;
		private final int[] arguments;
		
		public InstInvoke(VaMthInfo method, int object,
				boolean virtual, boolean result, int[] arguments) {
			this.mthInfo = method;
			this.object = object;
			this.virtual = virtual;
			this.result = result;
			this.arguments = arguments.clone();
		}
		
		// returns the argument count
		public int getArgumentCnt() {
			return arguments.length;
		}
		
		// returns the argument register at "index"
		public int getArgument(int index) {
			return arguments[index];
		}
	}
	
	// create a new object and push it onto the stack
	public static final class InstCreateObject extends VaInst {
		public final VaDatatype datatype;
		
		public InstCreateObject(VaDatatype datatype) {
			this.datatype = datatype;
		}
	}
	
	// creates a new array and push it onto the register stack
	public final static class InstCreateArray extends VaInst {
		public final VaDatatype datatype;
		public final int size;
		
		public InstCreateArray(VaDatatype datatype, int size) {
			this.datatype = datatype;
			this.size = size;
		}
	}

	// accesses an array element
	public final static class InstArrAccess extends VaInst {
		public static final int OP_STORE = 1;
		public static final int OP_LOAD = 2;
		
		public final int operator;
		public final int array;
		public final int index;
		public final int operand;
		
		public InstArrAccess(int operator, int array,
				int index, int operand) {
			this.array = array;
			this.operator = operator;
			this.index = index;
			this.operand = operand;
		}
	}
	
	// loads or stores a virtual register into a static
	// field or into an object field
	public final static class InstFldAccess extends VaInst {
		public static final int OP_STORE = 1;
		public static final int OP_LOAD = 2;
		
		public final VaFldInfo fldInfo;
		public final int operator;
		public final int object;
		public final int operand;
		
		public InstFldAccess(int operator, VaFldInfo fldinfo,
				int object, int operand) {
			this.fldInfo = fldinfo;
			this.operator = operator;
			this.object = object;
			this.operand = operand;
		}
	}
	
	// casts a register to a different type and stores the
	// new reference in a virtual register
	public final static class InstCast extends VaInst {
		public final VaDatatype datatype;
		public final int source;
		
		public InstCast(VaDatatype datatype, int source) {
			this.datatype = datatype;
			this.source = source;
		}
	}
	
	// pushs true onto the register stack if "object" is
	// an object of class "clsInfo".
	// otherwise false is pushed onto the stack.
	public final static class InstInstanceof extends VaInst {
		public final VaDatatype datatype;
		public final int object;
		
		public InstInstanceof(VaDatatype datatype, int object) {
			this.datatype = datatype;
			this.object = object;
		}
	}
	
	// constructs a delegate
	public final static class InstDlgConstruct extends VaInst {
		public final VaMthInfo method;
		public final int object;
		
		public InstDlgConstruct(final VaMthInfo method, final int object) {
			this.method = method;
			this.object = object;
		}
	}
	
	public final static class InstCatch extends VaInst {
		// the try-procedure of this catch statement
		public final VaProcedure procedure;
		// the frame that is invoked when an exception is thrown
		// and the frame that is invoked when the procedure finishes
		// the exception is stored in parameter 0
		// if no exception was thrown null is passed in parameter 0
		public final int frame;
		// arguments that are passed to the try-procedure
		private final int[] arguments;
		
		public InstCatch(final int frame, final int[] arguments,
				final VaProcedure procedure) {
			this.procedure = procedure;
			this.frame = frame;
			this.arguments = arguments.clone();
		}
		
		// returns the argument count
		public int getArgumentCnt() {
			return arguments.length;
		}
		
		// returns the argument register at "index"
		public int getArgument(int index) {
			return arguments[index];
		}
	}
	
	// specifies one return value of an exception handler
	// all return values must be specified in each frame of a try-procedure
	// before an instruction is executed that can raise an exception
	// parameter 0 must not be specified by this instruction
	public final static class InstPass extends VaInst {
		// the number of the return value we want to specify
		public final int argument;
		// the register that will be returned
		public final int register;
		
		public InstPass(final int argument, final int register) {
			this.argument = argument;
			this.register = register;
		}
	}
	
	// throws an exception
	public final static class InstThrow extends VaInst {
		// the register that contains the exception object
		// the exception must be a subclass of Korona.Exception
		public final int exception;
		
		public InstThrow(final int exception) {
			this.exception = exception;
		}
	}
	
	// leaves an exception handler
	public final static class InstLeave extends VaInst {
		
	}
	
	// returns the address of a method
	public final static class InstXNatMthAddress extends VaInst {
		public final VaMthInfo method;
		
		public InstXNatMthAddress(final VaMthInfo method) {
			this.method = method;
		}
	}
	
	public final static class InstXNatSizeofObject extends VaInst {
		public final VaDatatype datatype;
		
		public InstXNatSizeofObject(VaDatatype datatype) {
			this.datatype = datatype;
		}
	}
	
	// unsafe cast instruction
	public final static class InstXNatAddressCast extends VaInst {
		public final VaDatatype datatype;
		public final int address;
		
		public InstXNatAddressCast(VaDatatype datatype, int address) {
			this.datatype = datatype;
			this.address = address;
		}
	}
	
	public final static class InstXNatAddressOf extends VaInst {
		public static final int ADDRESS_OBJECT = 1;
		public static final int ADDRESS_DLG_OBJECT = 2;
		public static final int ADDRESS_DLG_METHOD = 3;
		
		public final int address;
		public final int object;
		
		public InstXNatAddressOf(int address, int object) {
			this.address = address;
			this.object = object;
		}
	}
	
	// constructs a class
	public final static class InstXNatMakeObject extends VaInst {
		public final VaClsInfo clsInfo;
		public final int address;
		
		public InstXNatMakeObject(final VaClsInfo clsinfo, final int address) {
			this.clsInfo = clsinfo;
			this.address = address;
		}
	}
	
	// constructs an array
	public final static class InstXNatMakeArray extends VaInst {
		public final VaDatatype datatype;
		public final int size;
		public final int address;
		
		public InstXNatMakeArray(final VaDatatype datatype,
				int size, final int address) {
			this.datatype = datatype;
			this.size = size;
			this.address = address;
		}
	}

	public final static class InstXNatMakeDelegate extends VaInst {
		public final VaDatatype datatype;
		public final int method;
		public final int object;
		
		public InstXNatMakeDelegate(final VaDatatype datatype,
				final int method, final int object) {
			this.datatype = datatype;
			this.method = method;
			this.object = object;
		}
	}
	
	public final static class InstXNatRefOperation extends VaInst {
		public static final int REF_INCREMENT = 1;
		public static final int REF_DECREMENT = 2;
		
		public final int operation;
		public final int register;
		
		public InstXNatRefOperation(final int operation, final int register) {
			this.operation = operation;
			this.register = register;
		}
	}
	
	public final static class InstXAtomCas extends VaInst {
		public final VaFldInfo field;
		public final int object;
		public final boolean result;
		public final int source;
		public final int value;
		
		public InstXAtomCas(VaFldInfo field, int object,
				int source, int value, boolean result) {
			this.field = field;
			this.object = object;
			this.source = source;
			this.value = value;
			this.result = result;
		}
	}
	
	public final static class InstXPerfArrayCopy extends VaInst {
		public final int dest;
		public final int source;
		public final int destOffset;
		public final int sourceOffset;
		public final int size;
		
		public InstXPerfArrayCopy(int dest, int source,
				int destoff, int srcoff, int size) {
			this.dest = dest;
			this.source = source;
			this.destOffset = destoff;
			this.sourceOffset = srcoff;
			this.size = size;
		}
	}
}
